package com.link.base.base.project.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.link.base.base.approval.model.Flow;
import com.link.base.base.approval.service.FlowService;
import com.link.base.base.product.model.PartHistoryPrice;
import com.link.base.base.product.service.PartHistoryPriceService;
import com.link.base.base.project.dao.mybatis.mapper.AcceptanceListMapper;
import com.link.base.base.project.dao.mybatis.mapper.ProjectMapper;
import com.link.base.base.project.model.AcceptanceList;
import com.link.base.base.project.model.AcceptanceParts;
import com.link.base.base.project.model.Project;
import com.link.base.core.basic.util.BigDecimalUtils;
import com.link.core.basic.dao.mapper.BasicMapper;
import com.link.core.basic.service.BasicServiceImpl;
import com.link.core.basic.service.ServiceException;
import com.link.core.util.DateUtil;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * 项目承接单
 *
 * @author 王昊
 * @date 2020-10-13 14:01:06
 */
@Service
public class AcceptanceListServiceImpl extends BasicServiceImpl<AcceptanceList> implements AcceptanceListService {

    @Resource
    private AcceptanceListMapper    acceptanceListMapper;

    @Resource
    private ProjectService projectService;

    @Resource
    private ProjectMapper projectMapper;

    @Resource
    private FlowService flowService;

    @Resource
    private ComptypeService comptypeService;

    @Resource
    private AcceptancePartsService acceptancePartsService;

    @Resource
    private PartHistoryPriceService partHistoryPriceService;

    @Override
    public BasicMapper<AcceptanceList> getBasicMapper() {
        return acceptanceListMapper;
    }

    /**
     * 项目编号：只读，自动生成。  弃 需求改为手工输入
     * 零件大类简写+****年份+3位流水号；例如PMZX2020001。
     * 零件大类取值从所选择的零件类型带的所属大类来，一个承接单会有多个零件类型，同时这零件类型都归属于一个大类；
     * 其中大类跟简称对应关系为塑料件-PMZX、顶灯-DZ、金属件-YY。
     * @param entity
     * @throws Exception
     */
//    @Override
//    public void beforInsert(AcceptanceList entity) throws Exception {
//        super.beforInsert(entity);
//        //判断前缀 判断承接单零件类型主要记录的零件的类型
//        Comptype comptype = new Comptype();
//        comptype.setId(entity.getPartTypeId());
//        Comptype comptype1 = comptypeService.queryById(comptype);
//        String prex ;
//        if ("Plastics".equals(comptype1.getCompProperty())) {
//            if ("顶灯".equals(comptype1.getCompType())) {
//                //顶灯
//                prex = "DZ";
//            } else {
//                //普通塑料件
//                prex = "PMZX";
//            }
//        } else {
//            //金属件
//            prex = "YY";
//        }
//        //获取年份
//        Calendar cal = Calendar.getInstance();
//        int year = cal.get(Calendar.YEAR);
//        //获取流水号
//        //获取redis操作对象 （参考方法setMpMpSingleDayPayNum
//        LinkRedisClient jedis = RedisUtil.getJedis();
//        try {
//            //判断以PROJECT_CODE_0 + prex为key的value值是否存在
//            String redisKey = "PROJECT_CODE_0" + prex;
//            String code2;
//            if (jedis.exists(redisKey)) {
//                // 存在的话直接取出来+1塞回去  4位流水号补零
//                String code = jedis.hget(redisKey,"partType");
//                int intcode = Integer.valueOf(code);
//                code2 = String.format("%04d",intcode);
//                jedis.hincrBy(redisKey,"partType",1);
//            } else {
//                // 不存在去数据库查编号 去查承接单编号以prex开头的最新记录
//                List<AcceptanceList> acceptanceLists = acceptanceListMapper.queryAllByProjectNum(prex);
//                if (acceptanceLists.size() != 0) {
//                    // 存在即（去查承接单编号以prex开头的最新记录 +1
//                    AcceptanceList acc = acceptanceLists.get(0);
//                    String projectNum = acc.getProjectNum();
//                    //String取后几位，String转数字 塞进去
//                    String result = projectNum.substring(projectNum.length() - 4);
//                    int intresult = Integer.valueOf(result);
//                    jedis.hset(redisKey , "partType", String.valueOf(++intresult));
//                    String code = jedis.hget(redisKey,"partType");
//                    int intcode = Integer.valueOf(code);
//                    code2 = String.format("%04d",intcode);
//                    //用完后再 +1
//                    jedis.hincrBy(redisKey,"partType",1);
//                } else {
//                    // 不存在即插入数值1
//                    jedis.hset(redisKey , "partType", String.valueOf(1));
//                    String code = jedis.hget(redisKey,"partType");
//                    int a4 = Integer.valueOf(code);
//                    code2 = String.format("%04d",a4);
//                }
//            }
//            entity.setProjectNum(prex + year + code2);
//        } catch (Exception e) {
//            LCLogger.withException(e);
//        } finally {
//            //关闭redis操作对象 释放资源
//            RedisUtil.returnResource(jedis);
//        }
//    }

    @Override
    public void beforInsert(AcceptanceList entity) throws Exception {
        /**
         * 20210521修改 承接单新建保存时为头项目赋值
         * 点击【生成承接单】按钮，并将承接单成功保存后，字段“是否定点”显示是。项目状态变为进行中,项目阶段变为定点阶段
         */
        //1.新建项目，将承接单项目id存入项目实体
        Project project = new Project();
        project.setId(entity.getProjectHeadId());
        //2.承接单新建保存时更新对应记录的‘是否定点’为 是，项目状态变为进行中，项目阶段变为定点阶段
        Project project1 = projectService.queryById(project);
        if (project1 != null) {
            project1.setWinFlag("Y");
            if ("Y".equals(project1.getWinFlag())) {
                project1.setProjectStatus("InTheProcess");
                project1.setProjectStage("FixedPointStage");
            }
            projectService.update(project1);
        }

    }


    /**
     * 承接单提交审批
     * @param entity
     * @throws Exception
     */
    @Override
    public void acceptanceListSubmit(AcceptanceList entity) throws Exception {
        AcceptanceList acce = acceptanceListMapper.queryById(entity);
        //1.将填写的承接单内容提交审批流，当承接单头字段“单据状态”为已提交或提交中时不可提交。
//        if (acce.getDocumentStatus().equals("Submitted")) {
//            throw new ServiceException("IYUACCEPLIST-001");
//        }

        String approvalType = "AcceptanceList";
        ObjectMapper mapper = new ObjectMapper();
        String approvalDetail = mapper.writeValueAsString(acce);
        //创建审批流程
        flowService.createFlow(acce.getId(), approvalType, null, acce.getAcctName(),acce.getId(), approvalDetail);
        acce.setDocumentStatus("Approvaling");
        acceptanceListMapper.update(acce);
    }

    /**
     * 承接单提交审批结果
     * @param flow
     * @param arg1
     * @param arg2
     * @param arg3
     * @param arg4
     * @param arg5
     * @throws Exception
     */
    @Override
    public void apprAcceptanceList(Flow flow, String arg1, String arg2, String arg3, String arg4, String arg5) throws Exception {
        Long acceptanceListId = flow.getFlowObjId();
        AcceptanceList accept = new AcceptanceList();
        accept.setId(acceptanceListId);
        accept.setDocumentStatus(arg1);
        acceptanceListMapper.updateStatus(accept);

        //承接单审批通过，状态为【已审批】时，将承接单产品行中零件插入至历史价格列表中
        if ("Approved".equals(accept.getDocumentStatus())) {
            //查询本承接单的所有产品行，将承接单产品行ID、CRM零件ID、总成报价ID、零件成本ID存入零件历史价格记录中用于关联其他信息
            AcceptanceParts querAccePart = new AcceptanceParts();
            querAccePart.setAcceptanceListId(accept.getId());
            List<AcceptanceParts> acceptanceParts = acceptancePartsService.queryAll(querAccePart);
            PartHistoryPrice partHistoryPrice = new PartHistoryPrice();
            for (AcceptanceParts acceptancePart : acceptanceParts) {
                partHistoryPrice.setId(keyGenerateService.keyGenerate());
                partHistoryPrice.setAccessPartId(acceptancePart.getId()); //承接单产品行ID
                partHistoryPrice.setCRMPartsId(acceptancePart.getCRMPartsId());  //零件ID
                partHistoryPrice.setCRMPartsCostId(acceptancePart.getCRMPartsCostId()); //CRM零件成本ID
                partHistoryPrice.setProdQuoteId(acceptancePart.getProdQuoteId()); //最新伦次总成报价ID
                partHistoryPriceService.insert(partHistoryPrice);
            }
        }
        // 更新前期项目项目状态为已关闭Closed
        AcceptanceList newAcceptanceList = acceptanceListMapper.queryById(accept);
        if (null == newAcceptanceList.getProjectHeadId()) {
            throw new RuntimeException("项目承接单不存在前期项目报价!");
        }
        Project project = new Project();
        project.setId(newAcceptanceList.getProjectHeadId());
        project.setProjectStatus("Closed");
        projectMapper.updateProjectStatus(project);
    }


    /**
     * 年度新项目承接管理表 拉平数据
     * @param entity
     * @return
     */
    @Override
    public List<AcceptanceList> projectUndertakingReport(AcceptanceList entity) throws Exception {
        //针对查询出来的每一个承接单记录对象，调用项目queryById方法，为每一个承接单实体set计算字段
        List<AcceptanceList> acceptanceLists = acceptanceListMapper.projectUndertakingReportPage(entity);
        if (!acceptanceLists.isEmpty()) {
            Project querProject = new Project();
            for (AcceptanceList acceptanceList : acceptanceLists) {
                querProject.setId(acceptanceList.getProjectHeadId());
                Project project = projectService.queryById(querProject);
                if (project != null) {
                    BigDecimal totalCarAmount = BigDecimalUtils.changeNullToZero(project.getTotalCarAmount());
                    BigDecimal avgQuotaCost = BigDecimalUtils.changeNullToZero(project.getAvgQuotaCost());
                    BigDecimal avgGrossing = BigDecimalUtils.changeNullToZero(project.getAvgGrossing());
                    //成本均车总价
                    acceptanceList.setTotalCarAmount(totalCarAmount);
                    //项目均车报价
                    acceptanceList.setAvgQuotaCost(avgQuotaCost);
                    //项目均车毛利率
                    acceptanceList.setAvgGrossing(avgGrossing);
                }
            }
        }

        return acceptanceLists;
    }

    /**
     * 项目承接实绩零件类型销售额报表（柱状图）
     * 根据日期范围查询承接单零件销售额并加和
     * @param entity
     * @return
     * @throws Exception
     */
    @Override
    public List queryAllByDate(AcceptanceList entity) throws Exception {
        //获取年份集合
        Set<String> years =  getYears(entity);
        //存放所有年份的零件年度销售额lists
        List<List<AcceptanceList>> partAnnualSales = new ArrayList<>();
        //存放所有不重复零件 这是x轴的最长长度
        Set<String> partTypeAll = new LinkedHashSet<>();
        //根据年份查询每一年的各零件销售额
        AcceptanceList querByYear = new AcceptanceList();

        for (String year : years) {
            if (!"product".equals(year)) {
                querByYear.setAttr1(year);
                List<AcceptanceList> acceptanceLists = acceptanceListMapper.queryAllByDate(querByYear);
                for (AcceptanceList acceptanceList : acceptanceLists) {
                    //遍历每一条零件记录，获取所有的零件类型id
                    String comptypeName =  acceptanceList.getComptypeName() == null ? "未知零件类型" : acceptanceList.getComptypeName();
                    partTypeAll.add(comptypeName);
                }
                partAnnualSales.add(acceptanceLists);
            }
        }
        //最终返回的实体
        List result = new ArrayList();
        result.add(years);
        boolean nohave = false;
        //遍历零件ID  partTypeAll 根据零件ID
        for (String part : partTypeAll) {
            List comp = new ArrayList();
            comp.add(part);
            //判断查询出来的list有没有该零件
            for (List<AcceptanceList> acceptanceLists : partAnnualSales) {
                if (acceptanceLists.size() == 0 || acceptanceLists.isEmpty()) {
                    nohave = true; //本年没有任何零件销售 ， 本零件当年销售额为0
                }
                for (AcceptanceList acceptanceList : acceptanceLists) {
                    if (part.equals(acceptanceList.getComptypeName())) {
                        //拿到今年的本零件销售额
                        comp.add(acceptanceList.getSumPartAnnualSales());
                        nohave = false;
                        break;
                    } else {
                        //当前年份没有本零件销售额
                        nohave = true;
                    }
                }
                if (nohave) {
                    //今年本零件销售额为0
                    comp.add("0");
                    nohave = false; //恢复默认值，方便下次循环调用
                }
            }
            result.add(comp);
        }
        return result;
    }



    /**
     * 项目承接实绩主机厂销售额报表（柱状图）
     * 根据日期范围查询承接单主机厂销售额并加和
     * @param entity
     * @return
     * @throws Exception
     */
    @Override
    public List queryAllByDateEnginee(AcceptanceList entity) throws Exception {
        //获取年份集合
        Set<String> years =  getYears(entity);
        //存放所有年份的主机厂年度销售额lists
        List<List<AcceptanceList>> engineAnnualSales = new ArrayList<>();
        //以key-value 的形式 顺序存放 主机厂ID-主机厂名称
        Map<Long,String> enginee = new LinkedHashMap<>();
        //根据年份查询每一年的各零件销售额
        AcceptanceList querByYear = new AcceptanceList();
        for (String year : years) {
            if (!"product".equals(year)) {
                querByYear.setAttr1(year);
                List<AcceptanceList> acceptanceLists = acceptanceListMapper.queryAllByDateEnginee(querByYear);
                for (AcceptanceList acceptanceList : acceptanceLists) {
                    //遍历每一条零件记录，获取所有的零件类型id
                    Long engineeId = acceptanceList.getEngineeId() == null ? new Long(111111111) : acceptanceList.getEngineeId();
                    String endAccntRoot =  acceptanceList.getEndAccntRoot() == null ? "未知主机厂" : acceptanceList.getEndAccntRoot();
                    enginee.put(engineeId,endAccntRoot);
                }
                engineAnnualSales.add(acceptanceLists);
            }
        }
        //最终返回的实体
        List result = new ArrayList();
        result.add(years);
        boolean nohave = false;
        //遍历主机厂map中的主机厂ID  keySet()返回这个map的所有key
        for (Long eng : enginee.keySet()) {
            List comp = new ArrayList();
            //返回指定key所映射的值
            comp.add(enginee.get(eng));
            //判断查询出来的list有没有该零件
            for (List<AcceptanceList> acceptanceLists : engineAnnualSales) {
                if (acceptanceLists.size() == 0) {
                    nohave = true; //本年没有任何零件销售 ， 本零件当年销售额为0
                }
                for (AcceptanceList acceptanceList : acceptanceLists) {
                    if (eng.equals(acceptanceList.getEngineeId())) {
                        //如果最外层拿的主机厂ID等于本年的这个主机厂的ID 拿到今年的本零件销售额
                        comp.add(acceptanceList.getSumPartAnnualSales());
                        nohave = false;
                        break;
                    } else {
                        //当前年份没有本零件销售额
                        nohave = true;
                    }
                }
                if (nohave) {
                    //今年本零件销售额为0
                    comp.add("0");
                    nohave = false; //恢复默认值，方便下次循环调用
                }
            }
            result.add(comp);
        }
        return result;
    }

    /**
     *根据传进来的两个年份，获取年份区间集合
     */
    public Set<String> getYears(AcceptanceList entity) throws Exception {
        //处理前端传过来的开始年份，结束年份 (传过来完整的日期格式 XXXX-01-01 12:00:00)
        //判空
        if (entity.getAttr2() == null || entity.getAttr3() == null) {
            //请选择开始及结束年份！
            throw new ServiceException("IYUPROJECT-011");
        }
        Date startYear = DateUtil.DATETIME_FORMATTER.parse(entity.getAttr2());
        Date endYear = DateUtil.DATETIME_FORMATTER.parse(entity.getAttr3());
        //判断起止时间大小
        if (startYear.after(endYear)) {
            //开始年份晚于结束年份，请重新选择年份！
            throw new ServiceException("IYUPROJECT-012");
        }
        //分离区间年份，塞入年份到list先返回一次  只要开始日期早于结束日期
        Set<String> years = new LinkedHashSet<>();
        years.add("product");
        Calendar cal = Calendar.getInstance();
        //想要startYear小于等于endYear的结果，就相当于startYear大于endYear的结果取反，就是！startYear.after(endYear)
        while (!startYear.after(endYear)) {
            cal.setTime(startYear);
            Integer addYear = cal.get(Calendar.YEAR);
            years.add(String.valueOf(addYear));
            startYear = DateUtil.addYearToDate(startYear, 1);//开始年份+1
        }
        return years;
    }
}
